package com.qmyx.supplychain.quartz.task;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.kuaidi100.sdk.api.QueryTrack;
import com.kuaidi100.sdk.enums.ExpressEnums;
import com.kuaidi100.sdk.request.QueryTrackParam;
import com.kuaidi100.sdk.request.QueryTrackReq;
import com.kuaidi100.sdk.response.QueryTrackResp;
import com.kuaidi100.sdk.utils.PropertiesReader;
import com.kuaidi100.sdk.utils.SignUtils;
import com.ytjj.qmyx.supplychain.common.constants.RedisConstants;
import com.ytjj.qmyx.supplychain.common.utils.DateUtil;
import com.ytjj.qmyx.supplychain.common.utils.RedisService;
import com.ytjj.qmyx.supplychain.mapper.ExpressOrdersMapper;
import com.ytjj.qmyx.supplychain.mapper.OrderExceptionMapper;
import com.ytjj.qmyx.supplychain.mapper.entity.YxExpressOrders;
import com.ytjj.qmyx.supplychain.mapper.entity.YxOrderException;
import com.ytjj.qmyx.supplychain.service.ExpressOrderService;
import com.ytjj.qmyx.supplychain.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * 订单快递查询定时任务
 */
@Component
@Slf4j
public class OrderExpressTask {
    @Value("${spring.profiles.active}")
    private String profiles;
    @Value("${expressLockTime:30}")
    private String expressLockTime;

    @Autowired
    private ExpressOrderService expressOrderService;
    @Autowired
    private OrderExceptionMapper orderExceptionMapper;
    @Resource
    private ExpressOrdersMapper expressOrdersMapper;
    @Resource
    private OrderService orderService;

    /**
     * 更新快递信息到物流表,并向快递100发起订阅
     * 从1分钟开始，每3分钟执行
     **/
    @Scheduled(cron = "0 1/3 * * * ?")
    public void ExpressInfoBack() {
        log.info("=============> 同步供应商系统快递信息到物流表开始");
        expressOrderService.expressInfoBack();
        log.info("=============> 同步供应商系统快递信息到物流表结束");
    }

    /**
     * 更新当天扫描到的【未签收】快递订单，更新物流
     * 从3分钟开始，每32分钟执行
     */
    @Scheduled(cron = "0 3/32 * * * ?")
    public void updateExpressOrdersStageOne(){
        log.info("===阶段1开始定时刷新快递订单状态===");
        LocalDateTime ldt = LocalDateTime.now(ZoneId.systemDefault()).minusMinutes(30);
        Date date = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
        List<YxExpressOrders> expressOrdersList = expressOrdersMapper.getExpressOrdersByIntervals(0,null,date);
        log.info("===阶段1待查询快递条数：{}", expressOrdersList.size());
        // 测试环境也获取物流信息
        if ("pd".equals(profiles) || "dev".equals(profiles)) {
            for (YxExpressOrders item : expressOrdersList) {
                if (!expressOrderService.getExpressLockForUpdate(item.getCompanyNo(), item.getExpressEno())) {
                    continue;
                }
                QueryTrack queryTrack = new QueryTrack();
                QueryTrackReq queryTrackReq = new QueryTrackReq();
                QueryTrackParam queryTrackParam = new QueryTrackParam();
                queryTrackParam.setCom(item.getCompanyNo());
                queryTrackParam.setNum(item.getExpressEno());
                queryTrackParam.setPhone(item.getPhone());
                queryTrackReq.setParam(queryTrackParam);
                queryTrackReq.setCustomer(PropertiesReader.get("customer"));
                queryTrackReq.setSign(SignUtils.sign(new Gson().toJson(queryTrackParam) + PropertiesReader.get("key") + PropertiesReader.get("customer")));
                QueryTrackResp resp = queryTrack.queryTrack(queryTrackReq);
                try {
                    expressOrderService.handleExpressResp(resp,item);
                } catch (Exception e) {
                    log.error("===阶段1定时刷新快递订单状态异常==={}", e);
                }
            }
        }
        log.info("===阶段1结束定时刷新快递订单状态===");
    }

    /**
     * 扫描到的快递天数在[1,3]区间内【未签收】快递,更新物流
     * 从23分开始，每1小时执行
     */
    @Scheduled(cron = "0 23/59 0/1 * * ?")
    public void updateExpressOrdersStageTwo() {
        log.info("===阶段2开始定时刷新快递订单状态===");
        LocalDateTime ldt = LocalDateTime.now(ZoneId.systemDefault()).minusHours(1);
        Date date = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
        List<YxExpressOrders> expressOrdersList= expressOrdersMapper.getExpressOrdersByIntervals(3,1,date);
        log.info("===阶段2待查询快递条数：{}",expressOrdersList.size());
        if ("pd".equals(profiles) || "dev".equals(profiles)) {
            for (YxExpressOrders item : expressOrdersList) {
                if (!expressOrderService.getExpressLockForUpdate(item.getCompanyNo(), item.getExpressEno())) {
                    continue;
                }
                QueryTrack queryTrack = new QueryTrack();
                QueryTrackReq queryTrackReq = new QueryTrackReq();
                QueryTrackParam queryTrackParam = new QueryTrackParam();
                queryTrackParam.setCom(item.getCompanyNo());
                queryTrackParam.setNum(item.getExpressEno());
                queryTrackParam.setPhone(item.getPhone());
                queryTrackReq.setParam(queryTrackParam);
                queryTrackReq.setCustomer(PropertiesReader.get("customer"));
                queryTrackReq.setSign(SignUtils.sign(new Gson().toJson(queryTrackParam) + PropertiesReader.get("key") + PropertiesReader.get("customer")));
                QueryTrackResp resp = queryTrack.queryTrack(queryTrackReq);
                try {
                    expressOrderService.handleExpressResp(resp,item);
                } catch (Exception e) {
                    log.error("===阶段2定时刷新快递订单状态异常==={}", e);
                }
            }
        }
        log.info("===阶段2结束定时刷新快递订单状态");
    }

    /**
     * 扫描到的快递天数在[4,12]区间内【未签收】快递,更新物流
     * 从5分开始，每4小时执行
     */
    @Scheduled(cron = "0 5/59 0/4 * * ?")
    public void updateExpressOrdersStageThree() {
        log.info("===阶段3开始定时刷新快递订单状态===");
        LocalDateTime ldt = LocalDateTime.now(ZoneId.systemDefault()).minusHours(1);
        Date date = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
        List<YxExpressOrders> expressOrdersList= expressOrdersMapper.getExpressOrdersByIntervals(12,4,date);
        log.info("===阶段3待查询快递条数：{}",expressOrdersList.size());
        if ("pd".equals(profiles) || "dev".equals(profiles)) {
            for (YxExpressOrders item : expressOrdersList) {
                if (!expressOrderService.getExpressLockForUpdate(item.getCompanyNo(), item.getExpressEno())) {
                    continue;
                }
                QueryTrack queryTrack = new QueryTrack();
                QueryTrackReq queryTrackReq = new QueryTrackReq();
                QueryTrackParam queryTrackParam = new QueryTrackParam();
                queryTrackParam.setCom(item.getCompanyNo());
                queryTrackParam.setNum(item.getExpressEno());
                queryTrackParam.setPhone(item.getPhone());
                queryTrackReq.setParam(queryTrackParam);
                queryTrackReq.setCustomer(PropertiesReader.get("customer"));
                queryTrackReq.setSign(SignUtils.sign(new Gson().toJson(queryTrackParam) + PropertiesReader.get("key") + PropertiesReader.get("customer")));
                QueryTrackResp resp = queryTrack.queryTrack(queryTrackReq);
                try {
                    expressOrderService.handleExpressResp(resp,item);
                } catch (Exception e) {
                    log.error("===阶段3定时刷新快递订单状态异常==={}", e);
                }
            }
        }
        log.info("===阶段3结束定时刷新快递订单状态");
    }

    /**
     * 扫描到的快递天数在[60,13]区间内【未签收】快递,更新物流
     * 每天凌晨1:03执行
     */
    @Scheduled(cron = "0 3 1 1/1 * ?")
    public void updateExpressOrdersStageFour() {
        log.info("===阶段4开始定时刷新快递订单状态===");
        LocalDateTime ldt = LocalDateTime.now(ZoneId.systemDefault()).minusHours(2);
        Date date = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
        List<YxExpressOrders> expressOrdersList = expressOrdersMapper.getExpressOrdersByIntervals(60, 13,date);
        log.info("===阶段4待查询快递条数：{}",expressOrdersList.size());
        if ("pd".equals(profiles) || "dev".equals(profiles)) {
            for (YxExpressOrders item : expressOrdersList) {
                if (!expressOrderService.getExpressLockForUpdate(item.getCompanyNo(), item.getExpressEno())) {
                    continue;
                }
                QueryTrack queryTrack = new QueryTrack();
                QueryTrackReq queryTrackReq = new QueryTrackReq();
                QueryTrackParam queryTrackParam = new QueryTrackParam();
                queryTrackParam.setCom(item.getCompanyNo());
                queryTrackParam.setNum(item.getExpressEno());
                queryTrackParam.setPhone(item.getPhone());
                queryTrackReq.setParam(queryTrackParam);
                queryTrackReq.setCustomer(PropertiesReader.get("customer"));
                queryTrackReq.setSign(SignUtils.sign(new Gson().toJson(queryTrackParam) + PropertiesReader.get("key") + PropertiesReader.get("customer")));
                QueryTrackResp resp = queryTrack.queryTrack(queryTrackReq);
                try {
                    expressOrderService.handleExpressResp(resp,item);
                } catch (Exception e) {
                    log.error("===阶段4定时刷新快递订单状态异常==={}", e);
                }
            }
        }
        log.info("===阶段4结束定时刷新快递订单状态");
    }


    /**
     * 查询今天【签收】的快递.
     * 防止有部分签收后又退回/拒收的订单，需要继续跟踪物流
     * 从9分开始，每小时执行
     */
    @Scheduled(cron = "0 9/59 0/1 * * ?")
    public void checkExpressSignAndRejectOne() {
        log.info("===开始处理今天【签收】的订单===");
        LocalDateTime ldt = LocalDateTime.now(ZoneId.systemDefault()).minusMinutes(40);
        Date date = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
        List<YxExpressOrders> expressOrdersList = expressOrdersMapper.getExpressForCheckByTime(0,0,date);
        log.info("===今天【签收】的条数有：{}", expressOrdersList.size());
        if ("pd".equals(profiles) || "dev".equals(profiles)) {
            for (YxExpressOrders item : expressOrdersList) {
                if (!expressOrderService.getExpressLockForUpdate(item.getCompanyNo(), item.getExpressEno())) {
                    continue;
                }
                QueryTrack queryTrack = new QueryTrack();
                QueryTrackReq queryTrackReq = new QueryTrackReq();
                QueryTrackParam queryTrackParam = new QueryTrackParam();
                queryTrackParam.setCom(item.getCompanyNo());
                queryTrackParam.setNum(item.getExpressEno());
                queryTrackParam.setPhone(item.getPhone());
                queryTrackReq.setParam(queryTrackParam);
                queryTrackReq.setCustomer(PropertiesReader.get("customer"));
                queryTrackReq.setSign(SignUtils.sign(new Gson().toJson(queryTrackParam) + PropertiesReader.get("key") + PropertiesReader.get("customer")));
                QueryTrackResp resp = queryTrack.queryTrack(queryTrackReq);
                try {
                    expressOrderService.handleExpressResp(resp, item);
                } catch (Exception e) {
                    log.error("===处理今天【签收】的快递订单出错==={}", e);
                }
            }
        }
        log.info("======结束处理今天【签收】的快递订单======");
    }

    /**
     * 查询昨天【签收】的快递.
     * 防止有部分签收后又退回/拒收的订单，需要继续跟踪物流
     * 从11分开始，每1小时执行
     */
    @Scheduled(cron = "0 11 0/1 * * ?")
    public void checkExpressSignAndRejectTwo() {
        log.info("===开始处理昨天【签收】的情况===");
        LocalDateTime ldt = LocalDateTime.now(ZoneId.systemDefault()).minusMinutes(40);
        Date date = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
        List<YxExpressOrders> expressOrdersList = expressOrdersMapper.getExpressForCheckByTime(1,0,date);
        log.info("===处理昨天【签收】的条数有：{}", expressOrdersList.size());
        if ("pd".equals(profiles) || "dev".equals(profiles)) {
            for (YxExpressOrders item : expressOrdersList) {
                if (!expressOrderService.getExpressLockForUpdate(item.getCompanyNo(), item.getExpressEno())) {
                    continue;
                }
                QueryTrack queryTrack = new QueryTrack();
                QueryTrackReq queryTrackReq = new QueryTrackReq();
                QueryTrackParam queryTrackParam = new QueryTrackParam();
                queryTrackParam.setCom(item.getCompanyNo());
                queryTrackParam.setNum(item.getExpressEno());
                queryTrackParam.setPhone(item.getPhone());
                queryTrackReq.setParam(queryTrackParam);
                queryTrackReq.setCustomer(PropertiesReader.get("customer"));
                queryTrackReq.setSign(SignUtils.sign(new Gson().toJson(queryTrackParam) + PropertiesReader.get("key") + PropertiesReader.get("customer")));
                QueryTrackResp resp = queryTrack.queryTrack(queryTrackReq);
                try {
                    expressOrderService.handleExpressResp(resp, item);
                } catch (Exception e) {
                    log.error("===处理昨天【签收】的快递订单出错==={}", e);
                }
            }
        }
        log.info("=======结束处理昨天【签收】的快递订单=======");
    }


    /**
     * 查询前7天【签收】的快递,并重新订阅。
     * 防止有部分签收后又退回/拒收的订单，需要继续跟踪物流
     * 每天凌晨02:17:00执行一次
     */
    @Scheduled(cron = "0 17 2 * * ?")
    public void checkExpressSignAndRejectThree() {
        log.info("===开始处理前天【签收】的情况===");
        LocalDateTime ldt = LocalDateTime.now(ZoneId.systemDefault()).minusMinutes(40);
        Date date = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
        List<YxExpressOrders> expressOrdersList = expressOrdersMapper.getExpressForCheckByTime(7,1,date);
        log.info("===前天【签收】的条数有：{}", expressOrdersList.size());
        if ("pd".equals(profiles) || "dev".equals(profiles)) {
            for (YxExpressOrders item : expressOrdersList) {
                orderService.subscribeExpress(item.getExpressEno(), item.getCompanyNo(), item.getPhone());
            }
        }
        log.info("======结束处理前天【签收】的快递订单======");
    }

    /**
     * 更新已发货35天内未签收的异常订单物流,快递100 计费规则：40天内同一个运单号多次查询不会重复扣费
     * 从2分钟开始，每35分钟执行
     */
    @Scheduled(cron = "0 2/35 * * * ?")
    public void updateExpressForChecked(){
        LocalDateTime ldt = LocalDateTime.now(ZoneId.systemDefault()).minusMinutes(40);
        Date date = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
        List<YxExpressOrders> trackList = orderExceptionMapper.getExceptionOrderToTrack(35,date);
        log.info("===开始定时刷新已签收并拒收的快递单，条数：{}===",trackList.size());
        // 测试环境也获取物流信息
        if ("pd".equals(profiles) || "dev".equals(profiles)) {
            for (YxExpressOrders item : trackList) {
                if (!expressOrderService.getExpressLockForUpdate(item.getCompanyNo(), item.getExpressEno())) {
                    continue;
                }
                QueryTrack queryTrack = new QueryTrack();
                QueryTrackReq queryTrackReq = new QueryTrackReq();
                QueryTrackParam queryTrackParam = new QueryTrackParam();
                queryTrackParam.setCom(item.getCompanyNo());
                queryTrackParam.setNum(item.getExpressEno());
                queryTrackParam.setPhone(item.getPhone());
                queryTrackReq.setParam(queryTrackParam);
                queryTrackReq.setCustomer(PropertiesReader.get("customer"));
                queryTrackReq.setSign(SignUtils.sign(new Gson().toJson(queryTrackParam) + PropertiesReader.get("key") + PropertiesReader.get("customer")));
                QueryTrackResp resp = queryTrack.queryTrack(queryTrackReq);
                try {
                    expressOrderService.handleExpressResp(resp,item);
                } catch (Exception e) {
                    log.error("===定时刷新已签收并拒收的快递单异常==={}", e);
                }
            }
        }
        log.info("===结束定时刷新已签收并拒收的快递单===");
    }

    /**
     * 查询无订单绑定关系的快递，设置为无效
     * 8分钟开始每25分钟执行一次
     */
    @Scheduled(cron = "0 8/25 * * * ?")
    public void updateExpressToInvalid() {
        List<YxExpressOrders> expressOrdersList= expressOrdersMapper.getExpressUnbound();
        if(CollectionUtils.isEmpty(expressOrdersList)){
            return;
        }
        List<Integer> ids = expressOrdersList.stream().map(YxExpressOrders::getId).collect(Collectors.toList());
        log.info("===开始处理无订单绑定的快递单：{}", JSON.toJSONString(ids));
        Integer integer = expressOrdersMapper.updateInvalidFlagById(ids);
        log.info("===已处理无订单绑定的快递单：{}", integer + "条");
    }

}
